package main

import (
	"fmt"
	"math"
	"os"
	"sort"
	"strings"
	"time"

	"github.com/xuri/excelize/v2"
)

// PriceData 价格数据（支持日线和周线）
type PriceData struct {
	Date        time.Time
	Close       float64
	ETFCode     string
	ReturnShort float64 // 短期收益率（周模式3周，日模式15天）
	ReturnLong  float64 // 长期收益率（周模式4周，日模式20天）
}

// WeeklyData 周线数据（兼容老代码）
type WeeklyData = PriceData

// Position 持仓
type Position struct {
	ETFCode string
	Shares  float64
	Price   float64
	Value   float64
	Weight  float64
}

// TradeRecord 交易记录
type TradeRecord struct {
	Date            time.Time
	ETFCode         string
	ETFName         string  // ETF名称
	Action          string  // BUY, SELL, HOLD
	Shares          float64
	Price           float64
	Amount          float64
	TradeWeight     float64 // 交易比例（占总资金的比例）
	PositionWeight  float64 // 交易后持仓比例
	Reason          string
	ProfitLoss      float64 // 盈亏金额（仅SELL时有效）
	ProfitLossRate  float64 // 盈亏比例（仅SELL时有效）
}

// ETF代码到名称的映射
var etfNameMap = map[string]string{
	"518880": "黄金ETF",
	"159941": "纳指ETF",
	"510300": "沪深300ETF",
	"511010": "国债ETF",
	"588050": "科创50ETF",
	"159915": "创业板ETF",
}

// getETFName 获取ETF名称
func getETFName(code string) string {
	if name, ok := etfNameMap[code]; ok {
		return name
	}
	return code
}

// BacktestResult 回测结果
type BacktestResult struct {
	Date           time.Time
	PortfolioValue float64
	Cash           float64
	Positions      []Position
	Trades         []TradeRecord
}

// PerformanceMetrics 绩效指标
type PerformanceMetrics struct {
	InitialCapital    float64
	FinalCapital      float64
	TotalReturn       float64
	AnnualReturn      float64
	AnnualVolatility  float64
	SharpeRatio       float64
	MaxDrawdown       float64
	WinRate           float64
	TradingWeeks      int
	TradingYears      float64
}

// ETFRotationStrategy ETF轮动策略
type ETFRotationStrategy struct {
	config        *Config
	data          map[string][]PriceData // ETFCode -> []PriceData
	dates         []time.Time
	results       []BacktestResult
	metrics       PerformanceMetrics
	allTrades     []TradeRecord          // 所有交易记录
	totalInvested float64                // 累计投入资金（包括初始+定投）
	costBasis     map[string]float64     // 每个ETF的成本价（加权平均）
	holdingShares map[string]float64     // 每个ETF的持仓股数（用于计算成本）
}

// NewETFRotationStrategy 创建策略实例
func NewETFRotationStrategy(config *Config) *ETFRotationStrategy {
	return &ETFRotationStrategy{
		config: config,
		data:   make(map[string][]PriceData),
	}
}

// LoadData 加载数据
func (s *ETFRotationStrategy) LoadData() error {
	f, err := excelize.OpenFile(s.config.DataFile)
	if err != nil {
		return fmt.Errorf("数据文件 %s 不存在，请先运行 scraper", s.config.DataFile)
	}
	defer f.Close()

	sheetName := "ETF周线数据"
	if s.config.RebalanceMode == "daily" {
		sheetName = "ETF日线数据"
	}
	rows, err := f.GetRows(sheetName)
	if err != nil {
		return err
	}

	dateMap := make(map[time.Time]bool)

	for i, row := range rows {
		if i == 0 || len(row) < 8 {
			continue // 跳过表头
		}

		date, err := time.Parse("2006-01-02", row[0])
		if err != nil {
			continue
		}

		close := parseFloat(row[2])
		etfCode := row[7]

		s.data[etfCode] = append(s.data[etfCode], PriceData{
			Date:    date,
			Close:   close,
			ETFCode: etfCode,
		})

		dateMap[date] = true
	}

	// 提取所有日期并排序
	for date := range dateMap {
		s.dates = append(s.dates, date)
	}
	sort.Slice(s.dates, func(i, j int) bool {
		return s.dates[i].Before(s.dates[j])
	})

	fmt.Printf("成功加载数据: %d 个ETF\n", len(s.data))
	fmt.Printf("日期范围: %s 至 %s\n", s.dates[0].Format("2006-01-02"), s.dates[len(s.dates)-1].Format("2006-01-02"))

	return nil
}

// CalculateMomentum 计算动量
func (s *ETFRotationStrategy) CalculateMomentum() {
	// 计算实际周期（日线模式下，3周=15天，4周=20天）
	shortPeriod := s.config.ShortPeriod
	longPeriod := s.config.LongPeriod
	if s.config.RebalanceMode == "daily" {
		shortPeriod = s.config.ShortPeriod * 5 // 3周 * 5天 = 15天
		longPeriod = s.config.LongPeriod * 5   // 4周 * 5天 = 20天
	}

	for code, data := range s.data {
		for i := range data {
			// 计算短期收益率
			if i >= shortPeriod-1 {
				data[i].ReturnShort = (data[i].Close - data[i-shortPeriod+1].Close) / data[i-shortPeriod+1].Close
			}
			// 计算长期收益率
			if i >= longPeriod-1 {
				data[i].ReturnLong = (data[i].Close - data[i-longPeriod+1].Close) / data[i-longPeriod+1].Close
			}
		}
		s.data[code] = data
	}
	fmt.Println("动量计算完成")
}

// GetPriceAtDate 获取指定日期的价格
func (s *ETFRotationStrategy) GetPriceAtDate(etfCode string, date time.Time) float64 {
	data, ok := s.data[etfCode]
	if !ok {
		return 0
	}

	for _, d := range data {
		if d.Date.Equal(date) {
			return d.Close
		}
	}
	return 0
}

// GetDataAtDate 获取指定日期的数据
func (s *ETFRotationStrategy) GetDataAtDate(etfCode string, date time.Time) *PriceData {
	data, ok := s.data[etfCode]
	if !ok {
		return nil
	}

	for _, d := range data {
		if d.Date.Equal(date) {
			return &d
		}
	}
	return nil
}

// SelectionInfo 选股信息
type SelectionInfo struct {
	Weights      map[string]float64 // ETF权重
	ShortReturns map[string]float64 // 短期涨幅
	LongReturns  map[string]float64 // 长期涨幅
	ShortRanks   map[string]int     // 短期排名
	LongRanks    map[string]int     // 长期排名
}

// SelectTopETFs 选择动量最强的ETF
// 新逻辑：分别根据短期和长期动量选出最强标的，如果是同一个则100%，否则各50%
// 如果两个周期的涨幅都小于阈值，则空仓
func (s *ETFRotationStrategy) SelectTopETFs(date time.Time) *SelectionInfo {
	type ETFReturn struct {
		Code   string
		Return float64
	}

	var shortReturns []ETFReturn
	var longReturns []ETFReturn

	// 只收集策略ETF池中的收益率（不包括基准ETF）
	for _, code := range s.config.ETFCodes {
		data := s.GetDataAtDate(code, date)
		if data == nil {
			continue
		}

		// 短期收益率
		if !math.IsNaN(data.ReturnShort) {
			shortReturns = append(shortReturns, ETFReturn{Code: code, Return: data.ReturnShort})
		}

		// 长期收益率
		if !math.IsNaN(data.ReturnLong) {
			longReturns = append(longReturns, ETFReturn{Code: code, Return: data.ReturnLong})
		}
	}

	if len(shortReturns) == 0 || len(longReturns) == 0 {
		return nil // 空仓
	}

	// 按收益率排序，找出最强的
	sort.Slice(shortReturns, func(i, j int) bool {
		return shortReturns[i].Return > shortReturns[j].Return
	})
	sort.Slice(longReturns, func(i, j int) bool {
		return longReturns[i].Return > longReturns[j].Return
	})

	// 构建排名和涨幅映射
	shortReturnMap := make(map[string]float64)
	longReturnMap := make(map[string]float64)
	shortRankMap := make(map[string]int)
	longRankMap := make(map[string]int)

	for i, er := range shortReturns {
		shortReturnMap[er.Code] = er.Return
		shortRankMap[er.Code] = i + 1
	}
	for i, er := range longReturns {
		longReturnMap[er.Code] = er.Return
		longRankMap[er.Code] = i + 1
	}

	shortBest := shortReturns[0]
	longBest := longReturns[0]

	// 检查是否满足最小收益率阈值
	if shortBest.Return <= s.config.MinReturn && longBest.Return <= s.config.MinReturn {
		return nil // 两个都不满足阈值，空仓
	}

	weights := make(map[string]float64)

	// 如果两个周期选中同一个标的
	if shortBest.Code == longBest.Code {
		// 检查该标的是否满足阈值
		if shortBest.Return > s.config.MinReturn {
			weights[shortBest.Code] = s.config.SingleETFWeight // 100%
		}
	} else {
		// 两个周期选中不同标的，各50%
		// 但只添加满足阈值的
		if shortBest.Return > s.config.MinReturn {
			weights[shortBest.Code] = s.config.DualETFWeight
		}
		if longBest.Return > s.config.MinReturn {
			if _, exists := weights[longBest.Code]; exists {
				// 如果已经存在（理论上不会发生），权重翻倍
				weights[longBest.Code] = s.config.SingleETFWeight
			} else {
				weights[longBest.Code] = s.config.DualETFWeight
			}
		}

		// 如果只有一个满足阈值，调整权重为100%
		if len(weights) == 1 {
			for code := range weights {
				weights[code] = s.config.SingleETFWeight
			}
		}
	}

	return &SelectionInfo{
		Weights:      weights,
		ShortReturns: shortReturnMap,
		LongReturns:  longReturnMap,
		ShortRanks:   shortRankMap,
		LongRanks:    longRankMap,
	}
}

// RunBacktest 运行回测
func (s *ETFRotationStrategy) RunBacktest(initialCapital float64) {
	fmt.Println("\n开始回测...")

	portfolioValue := initialCapital
	cash := initialCapital
	currentPositions := make(map[string]float64) // ETFCode -> Shares
	
	// 初始化成本跟踪
	s.costBasis = make(map[string]float64)
	s.holdingShares = make(map[string]float64)

	// 添加初始记录
	s.results = append(s.results, BacktestResult{
		Date:           s.dates[0],
		PortfolioValue: initialCapital,
		Cash:           cash,
		Positions:      []Position{},
		Trades:         []TradeRecord{},
	})

	// 确定开始位置（需要足够的历史数据）
	startPeriod := s.config.LongPeriod - 1
	if s.config.ShortPeriod-1 > startPeriod {
		startPeriod = s.config.ShortPeriod - 1
	}
	
	// 日线模式下，需要更多历史数据
	if s.config.RebalanceMode == "daily" {
		startPeriod = s.config.LongPeriod * 5 - 1
		if s.config.ShortPeriod*5-1 > startPeriod {
			startPeriod = s.config.ShortPeriod*5 - 1
		}
	}

	periodName := "周"
	if s.config.RebalanceMode == "daily" {
		periodName = "天"
	}
	fmt.Printf("从第 %d %s开始回测（需要 %d %s历史数据）\n", startPeriod+1, periodName, startPeriod+1, periodName)
	if s.config.MonthlyInvest > 0 {
		fmt.Printf("每月定投: ¥%.2f（每月15号补充，下次调仓生效）\n", s.config.MonthlyInvest)
	}

	// 记录待补充的资金和累计投入
	pendingCash := 0.0
	totalInvested := initialCapital // 累计投入（包括初始资金和定投）
	lastInvestMonth := -1

	// 从计算的开始位置开始
	for i := startPeriod; i < len(s.dates); i++ {
		currentDate := s.dates[i]
		weeklyTrades := []TradeRecord{}

		// 检查是否需要补充资金（每月15号之后的第一周）
		currentMonth := currentDate.Month()
		currentDay := currentDate.Day()
		if s.config.MonthlyInvest > 0 && int(currentMonth) != lastInvestMonth && currentDay >= 15 {
			pendingCash += s.config.MonthlyInvest
			totalInvested += s.config.MonthlyInvest
			lastInvestMonth = int(currentMonth)
			fmt.Printf("定投: %s，待补充资金 ¥%.2f（下次调仓生效）\n", 
				currentDate.Format("2006-01-02"), s.config.MonthlyInvest)
		}

		// 计算当前持仓价值
		currentValue := 0.0
		currentPositionsList := []Position{}
		
		for etfCode, shares := range currentPositions {
			price := s.GetPriceAtDate(etfCode, currentDate)
			if price > 0 {
				value := shares * price
				currentValue += value
				currentPositionsList = append(currentPositionsList, Position{
					ETFCode: etfCode,
					Shares:  shares,
					Price:   price,
					Value:   value,
					Weight:  0, // 稍后计算
				})
			}
		}

		if currentValue == 0 {
			currentValue = portfolioValue
		}

		portfolioValue = currentValue

		// 更新持仓权重
		for i := range currentPositionsList {
			currentPositionsList[i].Weight = currentPositionsList[i].Value / portfolioValue
		}

		// 选择新的ETF组合
		selection := s.SelectTopETFs(currentDate)
		
		var weights map[string]float64
		if selection != nil {
			weights = selection.Weights
		}

		// 如果有待补充的资金且需要调仓，则补充资金
		if pendingCash > 0 && len(weights) > 0 {
			portfolioValue += pendingCash
			fmt.Printf("调仓时补充资金: ¥%.2f，组合总值: ¥%.2f\n", pendingCash, portfolioValue)
			pendingCash = 0
		}

		// 构建新持仓和交易记录
		newPositions := make(map[string]float64)
		newPositionsList := []Position{}
		threshold := 0.01 // 交易阈值：0.01股

		// 第一阶段：处理所有需要卖出的（清仓或减仓）
		for etfCode, oldShares := range currentPositions {
			price := s.GetPriceAtDate(etfCode, currentDate)
			if price == 0 {
				continue
			}

			// 获取目标权重
			targetWeight := 0.0
			if weights != nil {
				if w, exists := weights[etfCode]; exists {
					targetWeight = w
				}
			}
			
			// 生成详细的卖出原因
			reason := "减仓"
			if targetWeight < 0.001 {
				reason = "不在新组合中"
				if selection != nil {
					shortReturn := selection.ShortReturns[etfCode]
					longReturn := selection.LongReturns[etfCode]
					shortRank := selection.ShortRanks[etfCode]
					longRank := selection.LongRanks[etfCode]
					reason = fmt.Sprintf("不在新组合中(短期涨幅%.3f%%排名%d,长期涨幅%.3f%%排名%d)", 
						shortReturn*100, shortRank, longReturn*100, longRank)
				}
			} else if selection != nil {
				shortReturn := selection.ShortReturns[etfCode]
				longReturn := selection.LongReturns[etfCode]
				shortRank := selection.ShortRanks[etfCode]
				longRank := selection.LongRanks[etfCode]
				reason = fmt.Sprintf("减仓(短期涨幅%.3f%%排名%d,长期涨幅%.3f%%排名%d)", 
					shortReturn*100, shortRank, longReturn*100, longRank)
			}

			// 计算目标股数
			targetAmount := portfolioValue * targetWeight
			targetShares := targetAmount / price

			// 判断是否需要卖出
			if oldShares - targetShares > threshold {
				deltaShares := oldShares - targetShares
				deltaAmount := deltaShares * price
				tradeWeight := deltaAmount / portfolioValue
				
				finalShares := targetShares
				
				// 如果目标权重接近0，完全清仓
				if targetWeight < 0.001 {
					deltaShares = oldShares
					deltaAmount = oldShares * price
					tradeWeight = deltaAmount / portfolioValue
					finalShares = 0
				}
				
				// 计算盈亏
				costPrice := s.costBasis[etfCode]
				profitLoss := 0.0
				profitLossRate := 0.0
				if costPrice > 0 {
					profitLoss = (price - costPrice) * deltaShares
					profitLossRate = (price - costPrice) / costPrice * 100
				}
				
				trade := TradeRecord{
					Date:           currentDate,
					ETFCode:        etfCode,
					ETFName:        getETFName(etfCode),
					Action:         "SELL",
					Shares:         deltaShares,
					Price:          price,
					Amount:         deltaAmount,
					TradeWeight:    tradeWeight,
					PositionWeight: targetWeight,
					Reason:         reason,
					ProfitLoss:     profitLoss,
					ProfitLossRate: profitLossRate,
				}
				weeklyTrades = append(weeklyTrades, trade)
				s.allTrades = append(s.allTrades, trade)
				
				// 更新持仓股数（用于计算成本）
				s.holdingShares[etfCode] = finalShares
				if finalShares <= threshold {
					delete(s.costBasis, etfCode)
					delete(s.holdingShares, etfCode)
				}
				
				// 更新为卖出后的股数
				if finalShares > threshold {
					newPositions[etfCode] = finalShares
				}
				// 如果finalShares <= threshold，不添加到newPositions（清仓）
			} else if targetWeight > 0.001 {
				// 不需要卖出，但在新组合中，保留当前持仓
				newPositions[etfCode] = oldShares
			}
			// 如果targetWeight <= 0.001且不需要卖出，说明已经清仓，不添加到newPositions
		}

		// 第二阶段：处理所有需要买入的（新买入或加仓）
		if weights != nil {
			for etfCode, weight := range weights {
				price := s.GetPriceAtDate(etfCode, currentDate)
				if price == 0 {
					continue
				}

				// 计算目标股数
				targetAmount := portfolioValue * weight
				targetShares := targetAmount / price
				
				// 获取当前持仓（可能在第一阶段已经更新过）
				currentShares := newPositions[etfCode]
				if currentShares == 0 {
					// 如果newPositions中没有，检查原始持仓
					currentShares = currentPositions[etfCode]
				}

				// 判断是否需要买入
				if targetShares - currentShares > threshold {
					deltaShares := targetShares - currentShares
					deltaAmount := deltaShares * price
					tradeWeight := deltaAmount / portfolioValue
					
					// 生成详细的买入原因
					reason := "加仓"
					if currentShares < threshold {
						reason = "新进入组合"
					}
					
					if selection != nil {
						shortReturn := selection.ShortReturns[etfCode]
						longReturn := selection.LongReturns[etfCode]
						shortRank := selection.ShortRanks[etfCode]
						longRank := selection.LongRanks[etfCode]
						
						if currentShares < threshold {
							reason = fmt.Sprintf("新进入组合(短期涨幅%.3f%%排名%d,长期涨幅%.3f%%排名%d)", 
								shortReturn*100, shortRank, longReturn*100, longRank)
						} else {
							reason = fmt.Sprintf("加仓(短期涨幅%.3f%%排名%d,长期涨幅%.3f%%排名%d)", 
								shortReturn*100, shortRank, longReturn*100, longRank)
						}
					}
					
					trade := TradeRecord{
						Date:           currentDate,
						ETFCode:        etfCode,
						ETFName:        getETFName(etfCode),
						Action:         "BUY",
						Shares:         deltaShares,
						Price:          price,
						Amount:         deltaAmount,
						TradeWeight:    tradeWeight,
						PositionWeight: weight,
						Reason:         reason,
						ProfitLoss:     0, // 买入时无盈亏
						ProfitLossRate: 0,
					}
					weeklyTrades = append(weeklyTrades, trade)
					s.allTrades = append(s.allTrades, trade)
					
					// 更新成本价（加权平均）
					oldHolding := s.holdingShares[etfCode]
					oldCost := s.costBasis[etfCode]
					newHolding := oldHolding + deltaShares
					if newHolding > 0 {
						s.costBasis[etfCode] = (oldCost*oldHolding + price*deltaShares) / newHolding
						s.holdingShares[etfCode] = newHolding
					}
				}

				// 设置最终持仓
				newPositions[etfCode] = targetShares
				newPositionsList = append(newPositionsList, Position{
					ETFCode: etfCode,
					Shares:  targetShares,
					Price:   price,
					Value:   targetShares * price,
					Weight:  weight,
				})
			}
		}

		// 记录结果 - 记录当周实际持仓（调仓前的持仓）
		s.results = append(s.results, BacktestResult{
			Date:           currentDate,  // 记录当周日期
			PortfolioValue: portfolioValue,
			Cash:           0, // 满仓策略，现金为0
			Positions:      currentPositionsList,  // 当周实际持仓（调仓前）
			Trades:         weeklyTrades,  // 当周的调仓交易
		})

		// 更新持仓为调仓后的新持仓
		currentPositions = newPositions
	}

	// 添加最后一周调仓后的持仓记录（如果有调仓）
	if len(s.results) > 0 {
		lastResult := s.results[len(s.results)-1]
		if len(lastResult.Trades) > 0 {
			// 最后一周有交易，需要记录调仓后的持仓
			lastDate := s.dates[len(s.dates)-1]
			
			// 计算最终持仓价值
			finalValue := 0.0
			var finalPositionsList []Position
			for etfCode, shares := range currentPositions {
				price := s.GetPriceAtDate(etfCode, lastDate)
				if price > 0 && shares > 0 {
					value := shares * price
					finalValue += value
					
					// 计算权重
					weight := 0.0
					if finalValue > 0 {
						weight = value / finalValue
					}
					
					finalPositionsList = append(finalPositionsList, Position{
						ETFCode: etfCode,
						Shares:  shares,
						Price:   price,
						Value:   value,
						Weight:  weight,
					})
				}
			}
			
			// 更新权重
			if finalValue > 0 {
				for i := range finalPositionsList {
					finalPositionsList[i].Weight = finalPositionsList[i].Value / finalValue
				}
			}
			
			// 添加最终持仓记录（日期为最后一天，无交易）
			s.results = append(s.results, BacktestResult{
				Date:           lastDate,
				PortfolioValue: finalValue,
				Cash:           0,
				Positions:      finalPositionsList,
				Trades:         []TradeRecord{}, // 无交易
			})
		}
	}

	// 保存累计投入资金
	s.totalInvested = totalInvested
	
	periodNameResult := "周"
	if s.config.RebalanceMode == "daily" {
		periodNameResult = "天"
	}
	fmt.Printf("回测完成，共 %d 个交易%s，%d 笔交易\n", len(s.results), periodNameResult, len(s.allTrades))
	fmt.Printf("累计投入: ¥%.2f（初始资金 + 定投）\n", totalInvested)
}

// CalculateMetrics 计算绩效指标
func (s *ETFRotationStrategy) CalculateMetrics() {
	if len(s.results) < 2 {
		fmt.Println("数据不足，无法计算指标")
		return
	}

	// 提取收益率序列
	var returns []float64
	for i := 1; i < len(s.results); i++ {
		ret := (s.results[i].PortfolioValue - s.results[i-1].PortfolioValue) / s.results[i-1].PortfolioValue
		returns = append(returns, ret)
	}

	initialCapital := s.results[0].PortfolioValue
	finalCapital := s.results[len(s.results)-1].PortfolioValue

	// 使用资金加权收益率（MWRR）- 考虑资金流入时间
	// 总收益 = 最终资金 - 累计投入
	totalProfit := finalCapital - s.totalInvested
	// 简单收益率 = 总收益 / 累计投入
	totalReturn := (totalProfit / s.totalInvested) * 100

	// 年化收益率（简化计算）
	periodsPerYear := 52.0
	if s.config.RebalanceMode == "daily" {
		periodsPerYear = 252.0 // 一年约252个交易日
	}
	years := float64(len(s.results)) / periodsPerYear
	// 如果没有定投，使用复合年化；有定投则使用简单年化
	annualReturn := 0.0
	if s.config.MonthlyInvest > 0 {
		// 有定投：使用简单年化（总收益率 / 年数）
		annualReturn = totalReturn / years
	} else {
		// 无定投：使用复合年化
		annualReturn = (math.Pow(finalCapital/initialCapital, 1/years) - 1) * 100
	}

	// 年化波动率
	volatility := stdDev(returns) * math.Sqrt(periodsPerYear) * 100

	// 夏普比率
	riskFreeRate := 0.03
	sharpeRatio := (annualReturn/100 - riskFreeRate) / (volatility / 100)

	// 最大回撤
	maxDrawdown := calculateMaxDrawdown(s.results)

	// 胜率
	wins := 0
	for _, ret := range returns {
		if ret > 0 {
			wins++
		}
	}
	winRate := float64(wins) / float64(len(returns)) * 100

	s.metrics = PerformanceMetrics{
		InitialCapital:   initialCapital,
		FinalCapital:     finalCapital,
		TotalReturn:      totalReturn,
		AnnualReturn:     annualReturn,
		AnnualVolatility: volatility,
		SharpeRatio:      sharpeRatio,
		MaxDrawdown:      maxDrawdown,
		WinRate:          winRate,
		TradingWeeks:     len(s.results),
		TradingYears:     years,
	}

	// 打印结果
	fmt.Println("\n" + strings.Repeat("=", 50))
	fmt.Println("回测绩效指标")
	fmt.Println(strings.Repeat("=", 50))
	fmt.Printf("初始资金:        ¥%.2f\n", s.metrics.InitialCapital)
	fmt.Printf("累计投入:        ¥%.2f\n", s.totalInvested)
	fmt.Printf("最终资金:        ¥%.2f\n", s.metrics.FinalCapital)
	fmt.Printf("总收益:          ¥%.2f\n", s.metrics.FinalCapital-s.totalInvested)
	fmt.Printf("总收益率:        %.2f%%（基于累计投入）\n", s.metrics.TotalReturn)
	fmt.Printf("年化收益率:      %.2f%%\n", s.metrics.AnnualReturn)
	fmt.Printf("年化波动率:      %.2f%%\n", s.metrics.AnnualVolatility)
	fmt.Printf("夏普比率:        %.2f\n", s.metrics.SharpeRatio)
	fmt.Printf("最大回撤:        %.2f%%\n", s.metrics.MaxDrawdown)
	fmt.Printf("胜率:            %.2f%%\n", s.metrics.WinRate)
	periodName := "周数"
	if s.config.RebalanceMode == "daily" {
		periodName = "天数"
	}
	fmt.Printf("回测%s:        %d\n", periodName, s.metrics.TradingWeeks)
	fmt.Printf("回测年数:        %.2f\n", s.metrics.TradingYears)
	fmt.Println(strings.Repeat("=", 50))
}

// PlotEquityCurve 绘制收益曲线并生成完整的HTML报告
func (s *ETFRotationStrategy) PlotEquityCurve(filename string) error {
	// 保存为HTML
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	// 写入HTML头部和样式
	fmt.Fprintf(f, `<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ETF轮动策略回测结果</title>
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
    <style>
        body {
            font-family: 'Microsoft YaHei', Arial, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f5f5f5;
        }
        .container {
            max-width: 1400px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }
        h1 {
            color: #333;
            border-bottom: 3px solid #1890ff;
            padding-bottom: 10px;
        }
        h2 {
            color: #666;
            margin-top: 30px;
        }
        .metrics {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }
        .metric-card {
            background: linear-gradient(135deg, #667eea 0%%, #764ba2 100%%);
            color: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
        }
        .metric-card.positive {
            background: linear-gradient(135deg, #f093fb 0%%, #f5576c 100%%);
        }
        .metric-card.neutral {
            background: linear-gradient(135deg, #4facfe 0%%, #00f2fe 100%%);
        }
        .metric-label {
            font-size: 14px;
            opacity: 0.9;
        }
        .metric-value {
            font-size: 28px;
            font-weight: bold;
            margin-top: 10px;
        }
        .chart {
            width: 100%%;
            height: 500px;
            margin: 20px 0;
        }
        table {
            width: 100%%;
            border-collapse: collapse;
            margin: 20px 0;
        }
        th, td {
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }
        th {
            background-color: #1890ff;
            color: white;
            font-weight: bold;
        }
        tr:hover {
            background-color: #f5f5f5;
        }
        .buy {
            color: #52c41a;
            font-weight: bold;
        }
        .sell {
            color: #f5222d;
            font-weight: bold;
        }
        .tab-container {
            margin: 20px 0;
        }
        .tabs {
            display: flex;
            border-bottom: 2px solid #1890ff;
            margin-bottom: 20px;
        }
        .tab {
            padding: 10px 20px;
            cursor: pointer;
            background: #f0f0f0;
            border: none;
            margin-right: 5px;
            border-radius: 4px 4px 0 0;
        }
        .tab.active {
            background: #1890ff;
            color: white;
        }
        .tab-content {
            display: none;
        }
        .tab-content.active {
            display: block;
        }
        .scroll-table {
            max-height: 600px;
            overflow-y: auto;
        }
        .time-btn {
            padding: 8px 16px;
            margin-right: 8px;
            margin-bottom: 8px;
            cursor: pointer;
            background: #f0f0f0;
            border: 1px solid #d9d9d9;
            border-radius: 4px;
            font-size: 14px;
            transition: all 0.3s;
        }
        .time-btn:hover {
            background: #e6f7ff;
            border-color: #1890ff;
            color: #1890ff;
        }
        .time-btn.active {
            background: #1890ff;
            color: white;
            border-color: #1890ff;
        }
        .buy {
            color: #cf1322;
            font-weight: bold;
        }
        .sell {
            color: #389e0d;
            font-weight: bold;
        }
        .profit {
            color: #cf1322;
            font-weight: bold;
        }
        .loss {
            color: #389e0d;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>📊 ETF轮动策略回测报告</h1>
        
        <div class="metrics">
            <div class="metric-card">
                <div class="metric-label">初始资金</div>
                <div class="metric-value">¥%.0f</div>
            </div>
            <div class="metric-card positive">
                <div class="metric-label">最终资金</div>
                <div class="metric-value">¥%.0f</div>
            </div>
            <div class="metric-card">
                <div class="metric-label">总收益率</div>
                <div class="metric-value">%.2f%%</div>
            </div>
            <div class="metric-card neutral">
                <div class="metric-label">年化收益率</div>
                <div class="metric-value">%.2f%%</div>
            </div>
            <div class="metric-card">
                <div class="metric-label">夏普比率</div>
                <div class="metric-value">%.2f</div>
            </div>
            <div class="metric-card">
                <div class="metric-label">最大回撤</div>
                <div class="metric-value">%.2f%%</div>
            </div>
        </div>

        <h2>📈 资金曲线</h2>
        <div style="margin: 10px 0;">
            <button class="time-btn" onclick="setTimeRange('all')">全部</button>
            <button class="time-btn" onclick="setTimeRange('3y')">近3年</button>
            <button class="time-btn" onclick="setTimeRange('2y')">近2年</button>
            <button class="time-btn" onclick="setTimeRange('1y')">近1年</button>
            <button class="time-btn" onclick="setTimeRange('6m')">近半年</button>
            <button class="time-btn" onclick="setTimeRange('3m')">近3月</button>
            <button class="time-btn" onclick="setTimeRange('1m')">近1月</button>
            <button class="time-btn" onclick="setTimeRange('1w')">近1周</button>
        </div>
        <div id="equityChart" class="chart"></div>

        <h2>📉 回撤曲线</h2>
        <div id="drawdownChart" class="chart"></div>

        <div class="tab-container">
            <div class="tabs">
                <button class="tab active" onclick="showTab('trades')">交易记录</button>
                <button class="tab" onclick="showTab('positions')">持仓明细</button>
            </div>

            <div id="trades" class="tab-content active">
                <h2>💼 交易记录（共%d笔）</h2>
                <div class="scroll-table">
                    <table>
                        <thead>
                            <tr>
                                <th>日期</th>
                                <th>ETF代码</th>
                                <th>ETF名称</th>
                                <th>操作</th>
                                <th>股数</th>
                                <th>价格</th>
                                <th>金额</th>
                                <th>交易比例</th>
                                <th>持仓比例</th>
                                <th>盈亏金额</th>
                                <th>盈亏比例</th>
                                <th>原因</th>
                            </tr>
                        </thead>
                        <tbody>
`, s.metrics.InitialCapital, s.metrics.FinalCapital, s.metrics.TotalReturn, 
   s.metrics.AnnualReturn, s.metrics.SharpeRatio, s.metrics.MaxDrawdown, len(s.allTrades))

	// 写入交易记录
	for _, trade := range s.allTrades {
		actionClass := "buy"
		if trade.Action == "SELL" {
			actionClass = "sell"
		}
		
		profitLossStr := "-"
		profitLossRateStr := "-"
		profitLossClass := ""
		if trade.Action == "SELL" && trade.ProfitLoss != 0 {
			profitLossStr = fmt.Sprintf("%.2f", trade.ProfitLoss)
			profitLossRateStr = fmt.Sprintf("%.3f%%", trade.ProfitLossRate)
			if trade.ProfitLoss > 0 {
				profitLossClass = "profit"
			} else {
				profitLossClass = "loss"
			}
		}
		
		fmt.Fprintf(f, `                            <tr>
                                <td>%s</td>
                                <td>%s</td>
                                <td>%s</td>
                                <td class="%s">%s</td>
                                <td>%.3f</td>
                                <td>%.3f</td>
                                <td>%.2f</td>
                                <td>%.1f%%</td>
                                <td>%.1f%%</td>
                                <td class="%s">%s</td>
                                <td class="%s">%s</td>
                                <td>%s</td>
                            </tr>
`, trade.Date.Format("2006-01-02"), trade.ETFCode, trade.ETFName, actionClass, trade.Action,
		trade.Shares, trade.Price, trade.Amount, trade.TradeWeight*100, trade.PositionWeight*100,
		profitLossClass, profitLossStr, profitLossClass, profitLossRateStr, trade.Reason)
	}

	fmt.Fprintf(f, `                        </tbody>
                    </table>
                </div>
            </div>

            <div id="positions" class="tab-content">
                <h2>📋 持仓明细（按周）</h2>
                <div class="scroll-table">
                    <table>
                        <thead>
                            <tr>
                                <th>日期</th>
                                <th>ETF代码</th>
                                <th>ETF名称</th>
                                <th>持仓股数</th>
                                <th>价格</th>
                                <th>市值</th>
                                <th>权重</th>
                                <th>组合总值</th>
                            </tr>
                        </thead>
                        <tbody>
`)

	// 写入持仓记录
	for _, result := range s.results {
		if len(result.Positions) == 0 {
			fmt.Fprintf(f, `                            <tr>
                                <td>%s</td>
                                <td colspan="6">空仓</td>
                                <td>%.2f</td>
                            </tr>
`, result.Date.Format("2006-01-02"), result.PortfolioValue)
		} else {
			for _, pos := range result.Positions {
				fmt.Fprintf(f, `                            <tr>
                                <td>%s</td>
                                <td>%s</td>
                                <td>%s</td>
                                <td>%.3f</td>
                                <td>%.3f</td>
                                <td>%.2f</td>
                                <td>%.1f%%</td>
                                <td>%.2f</td>
                            </tr>
`, result.Date.Format("2006-01-02"), pos.ETFCode, getETFName(pos.ETFCode), pos.Shares, pos.Price, pos.Value, pos.Weight*100, result.PortfolioValue)
			}
		}
	}

	// 准备图表数据
	var dates []string
	var values []float64
	var drawdowns []float64
	var benchmark510300 []float64

	// 准备沪深300基准数据
	has510300 := false
	var benchmark510300Data []WeeklyData
	if data510300, ok := s.data["510300"]; ok {
		has510300 = true
		benchmark510300Data = data510300
	}

	maxValue := s.results[0].PortfolioValue
	initialValue := s.results[0].PortfolioValue
	
	for i, result := range s.results {
		dates = append(dates, result.Date.Format("2006-01-02"))
		values = append(values, result.PortfolioValue)

		// 计算回撤
		if result.PortfolioValue > maxValue {
			maxValue = result.PortfolioValue
		}
		dd := (result.PortfolioValue - maxValue) / maxValue * 100
		drawdowns = append(drawdowns, dd)

		// 计算沪深300基准（归一化到初始资金）
		if has510300 && i < len(benchmark510300Data) {
			// 找到对应日期的510300数据
			var benchmarkPrice float64
			for _, data := range benchmark510300Data {
				if data.Date.Equal(result.Date) {
					benchmarkPrice = data.Close
					break
				}
			}
			
			if benchmarkPrice > 0 && i == 0 {
				// 第一个点，记录初始价格
				benchmark510300 = append(benchmark510300, initialValue)
			} else if benchmarkPrice > 0 && len(benchmark510300Data) > 0 {
				// 计算相对于第一个点的涨幅
				firstPrice := benchmark510300Data[0].Close
				if firstPrice > 0 {
					benchmarkValue := initialValue * (benchmarkPrice / firstPrice)
					benchmark510300 = append(benchmark510300, benchmarkValue)
				} else {
					benchmark510300 = append(benchmark510300, initialValue)
				}
			} else {
				benchmark510300 = append(benchmark510300, initialValue)
			}
		}
	}

	// 写入JavaScript代码
	fmt.Fprintf(f, `                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>

    <script>
        function showTab(tabName) {
            // 隐藏所有标签页
            var contents = document.getElementsByClassName('tab-content');
            for (var i = 0; i < contents.length; i++) {
                contents[i].classList.remove('active');
            }
            
            // 移除所有按钮的active类
            var tabs = document.getElementsByClassName('tab');
            for (var i = 0; i < tabs.length; i++) {
                tabs[i].classList.remove('active');
            }
            
            // 显示选中的标签页
            document.getElementById(tabName).classList.add('active');
            event.target.classList.add('active');
        }

        // 资金曲线图
        var equityChart = echarts.init(document.getElementById('equityChart'));
        var dates = %s;
        var values = %s;
        var benchmark510300 = %s;
        var has510300 = %v;
        
        // 时间范围选择函数
        function setTimeRange(range) {
            var end = 100;
            var start = 0;
            var totalDays = dates.length;
            
            switch(range) {
                case '1w':
                    start = Math.max(0, 100 - (7 / (totalDays * 7)) * 100);
                    break;
                case '1m':
                    start = Math.max(0, 100 - (30 / (totalDays * 7)) * 100);
                    break;
                case '3m':
                    start = Math.max(0, 100 - (90 / (totalDays * 7)) * 100);
                    break;
                case '6m':
                    start = Math.max(0, 100 - (180 / (totalDays * 7)) * 100);
                    break;
                case '1y':
                    start = Math.max(0, 100 - (365 / (totalDays * 7)) * 100);
                    break;
                case '2y':
                    start = Math.max(0, 100 - (730 / (totalDays * 7)) * 100);
                    break;
                case '3y':
                    start = Math.max(0, 100 - (1095 / (totalDays * 7)) * 100);
                    break;
                case 'all':
                default:
                    start = 0;
                    break;
            }
            
            equityChart.dispatchAction({
                type: 'dataZoom',
                start: start,
                end: end
            });
            
            // 更新按钮状态
            var btns = document.getElementsByClassName('time-btn');
            for (var i = 0; i < btns.length; i++) {
                btns[i].classList.remove('active');
            }
            event.target.classList.add('active');
        }
        
        var seriesData = [{
            name: '组合价值',
            type: 'line',
            data: values,
            smooth: true,
            lineStyle: {
                width: 2,
                color: '#1890ff'
            },
            areaStyle: {
                color: {
                    type: 'linear',
                    x: 0, y: 0, x2: 0, y2: 1,
                    colorStops: [{
                        offset: 0, color: 'rgba(24, 144, 255, 0.3)'
                    }, {
                        offset: 1, color: 'rgba(24, 144, 255, 0.05)'
                    }]
                }
            }
        }];
        
        // 如果有沪深300数据，添加基准线
        if (has510300 && benchmark510300.length > 0) {
            seriesData.push({
                name: '沪深300',
                type: 'line',
                data: benchmark510300,
                smooth: true,
                lineStyle: {
                    width: 2,
                    color: '#ff7875',
                    type: 'dashed'
                }
            });
        }
        
        var equityOption = {
            tooltip: {
                trigger: 'axis',
                formatter: function(params) {
                    var result = params[0].axisValue + '<br/>';
                    for (var i = 0; i < params.length; i++) {
                        var value = params[i].data;
                        var startIndex = Math.floor(dates.length * equityChart.getOption().dataZoom[0].start / 100);
                        var baseValue = i === 0 ? values[startIndex] : benchmark510300[startIndex];
                        var returnPct = ((value - baseValue) / baseValue * 100).toFixed(2);
                        result += params[i].marker + params[i].seriesName + ': ¥' + value.toFixed(2) + 
                                  ' (区间收益: ' + returnPct + '%%)' + '<br/>';
                    }
                    return result;
                }
            },
            legend: {
                data: has510300 ? ['组合价值', '沪深300'] : ['组合价值'],
                top: 10
            },
            xAxis: {
                type: 'category',
                data: dates,
                boundaryGap: false
            },
            yAxis: {
                type: 'value',
                axisLabel: {
                    formatter: '¥{value}'
                }
            },
            dataZoom: [{
                type: 'slider',
                start: 0,
                end: 100,
                handleSize: 8
            }, {
                type: 'inside'
            }],
            series: seriesData
        };
        
        equityChart.setOption(equityOption);

        // 回撤曲线图
        var drawdownChart = echarts.init(document.getElementById('drawdownChart'));
        var drawdowns = %s;
        
        var drawdownOption = {
            tooltip: {
                trigger: 'axis',
                formatter: function(params) {
                    return params[0].axisValue + '<br/>回撤: ' + params[0].data.toFixed(2) + '%';
                }
            },
            xAxis: {
                type: 'category',
                data: dates,
                boundaryGap: false
            },
            yAxis: {
                type: 'value',
                axisLabel: {
                    formatter: '{value}%%'
                }
            },
            dataZoom: [{
                type: 'slider',
                start: 0,
                end: 100,
                handleSize: 8
            }, {
                type: 'inside'
            }],
            series: [{
                name: '回撤',
                type: 'line',
                data: drawdowns,
                smooth: true,
                lineStyle: {
                    width: 2,
                    color: '#f5222d'
                },
                areaStyle: {
                    color: {
                        type: 'linear',
                        x: 0, y: 0, x2: 0, y2: 1,
                        colorStops: [{
                            offset: 0, color: 'rgba(245, 34, 45, 0.3)'
                        }, {
                            offset: 1, color: 'rgba(245, 34, 45, 0.05)'
                        }]
                    }
                }
            }]
        };
        
        drawdownChart.setOption(drawdownOption);

        // 响应窗口大小变化
        window.addEventListener('resize', function() {
            equityChart.resize();
            drawdownChart.resize();
        });
    </script>
</body>
</html>
`, toJSONArray(dates), toJSONFloatArray(values), toJSONFloatArray(benchmark510300), has510300, toJSONFloatArray(drawdowns))

	fmt.Printf("\n收益曲线已保存到 %s\n", filename)
	return nil
}

// toJSONArray 将字符串数组转换为JSON数组
func toJSONArray(arr []string) string {
	result := "["
	for i, v := range arr {
		if i > 0 {
			result += ","
		}
		result += fmt.Sprintf(`"%s"`, v)
	}
	result += "]"
	return result
}

// toJSONFloatArray 将浮点数组转换为JSON数组
func toJSONFloatArray(arr []float64) string {
	result := "["
	for i, v := range arr {
		if i > 0 {
			result += ","
		}
		result += fmt.Sprintf("%.2f", v)
	}
	result += "]"
	return result
}

// SaveResults 保存回测结果
func (s *ETFRotationStrategy) SaveResults(filename string) error {
	f := excelize.NewFile()
	defer f.Close()

	// Sheet 1: 资金曲线
	sheet1 := "资金曲线"
	index1, _ := f.NewSheet(sheet1)
	f.SetCellValue(sheet1, "A1", "日期")
	f.SetCellValue(sheet1, "B1", "组合价值")
	f.SetCellValue(sheet1, "C1", "现金")

	for i, result := range s.results {
		row := i + 2
		f.SetCellValue(sheet1, fmt.Sprintf("A%d", row), result.Date.Format("2006-01-02"))
		f.SetCellValue(sheet1, fmt.Sprintf("B%d", row), result.PortfolioValue)
		f.SetCellValue(sheet1, fmt.Sprintf("C%d", row), result.Cash)
	}

	// Sheet 2: 绩效指标
	sheet2 := "绩效指标"
	f.NewSheet(sheet2)
	f.SetCellValue(sheet2, "A1", "指标")
	f.SetCellValue(sheet2, "B1", "数值")
	f.SetCellValue(sheet2, "A2", "初始资金")
	f.SetCellValue(sheet2, "B2", s.metrics.InitialCapital)
	f.SetCellValue(sheet2, "A3", "最终资金")
	f.SetCellValue(sheet2, "B3", s.metrics.FinalCapital)
	f.SetCellValue(sheet2, "A4", "总收益率(%)")
	f.SetCellValue(sheet2, "B4", s.metrics.TotalReturn)
	f.SetCellValue(sheet2, "A5", "年化收益率(%)")
	f.SetCellValue(sheet2, "B5", s.metrics.AnnualReturn)
	f.SetCellValue(sheet2, "A6", "年化波动率(%)")
	f.SetCellValue(sheet2, "B6", s.metrics.AnnualVolatility)
	f.SetCellValue(sheet2, "A7", "夏普比率")
	f.SetCellValue(sheet2, "B7", s.metrics.SharpeRatio)
	f.SetCellValue(sheet2, "A8", "最大回撤(%)")
	f.SetCellValue(sheet2, "B8", s.metrics.MaxDrawdown)
	f.SetCellValue(sheet2, "A9", "胜率(%)")
	f.SetCellValue(sheet2, "B9", s.metrics.WinRate)
	f.SetCellValue(sheet2, "A10", "总交易次数")
	f.SetCellValue(sheet2, "B10", len(s.allTrades))

	// Sheet 3: 交易记录
	sheet3 := "交易记录"
	f.NewSheet(sheet3)
	f.SetCellValue(sheet3, "A1", "日期")
	f.SetCellValue(sheet3, "B1", "ETF代码")
	f.SetCellValue(sheet3, "C1", "ETF名称")
	f.SetCellValue(sheet3, "D1", "操作")
	f.SetCellValue(sheet3, "E1", "股数")
	f.SetCellValue(sheet3, "F1", "价格")
	f.SetCellValue(sheet3, "G1", "金额")
	f.SetCellValue(sheet3, "H1", "交易比例(%)")
	f.SetCellValue(sheet3, "I1", "持仓比例(%)")
	f.SetCellValue(sheet3, "J1", "盈亏金额")
	f.SetCellValue(sheet3, "K1", "盈亏比例(%)")
	f.SetCellValue(sheet3, "L1", "原因")

	for i, trade := range s.allTrades {
		row := i + 2
		f.SetCellValue(sheet3, fmt.Sprintf("A%d", row), trade.Date.Format("2006-01-02"))
		f.SetCellValue(sheet3, fmt.Sprintf("B%d", row), trade.ETFCode)
		f.SetCellValue(sheet3, fmt.Sprintf("C%d", row), trade.ETFName)
		f.SetCellValue(sheet3, fmt.Sprintf("D%d", row), trade.Action)
		f.SetCellValue(sheet3, fmt.Sprintf("E%d", row), trade.Shares)
		f.SetCellValue(sheet3, fmt.Sprintf("F%d", row), trade.Price)
		f.SetCellValue(sheet3, fmt.Sprintf("G%d", row), trade.Amount)
		f.SetCellValue(sheet3, fmt.Sprintf("H%d", row), trade.TradeWeight*100)
		f.SetCellValue(sheet3, fmt.Sprintf("I%d", row), trade.PositionWeight*100)
		if trade.Action == "SELL" && trade.ProfitLoss != 0 {
			f.SetCellValue(sheet3, fmt.Sprintf("J%d", row), trade.ProfitLoss)
			f.SetCellValue(sheet3, fmt.Sprintf("K%d", row), trade.ProfitLossRate)
		}
		f.SetCellValue(sheet3, fmt.Sprintf("L%d", row), trade.Reason)
	}

	// Sheet 4: 持仓明细
	sheet4 := "持仓明细"
	f.NewSheet(sheet4)
	f.SetCellValue(sheet4, "A1", "日期")
	f.SetCellValue(sheet4, "B1", "ETF代码")
	f.SetCellValue(sheet4, "C1", "持仓股数")
	f.SetCellValue(sheet4, "D1", "持仓价格")
	f.SetCellValue(sheet4, "E1", "持仓市值")
	f.SetCellValue(sheet4, "F1", "持仓权重(%)")
	f.SetCellValue(sheet4, "G1", "组合总值")

	row := 2
	for _, result := range s.results {
		if len(result.Positions) == 0 {
			// 空仓时也记录一行
			f.SetCellValue(sheet4, fmt.Sprintf("A%d", row), result.Date.Format("2006-01-02"))
			f.SetCellValue(sheet4, fmt.Sprintf("B%d", row), "空仓")
			f.SetCellValue(sheet4, fmt.Sprintf("G%d", row), result.PortfolioValue)
			row++
		} else {
			for _, pos := range result.Positions {
				f.SetCellValue(sheet4, fmt.Sprintf("A%d", row), result.Date.Format("2006-01-02"))
				f.SetCellValue(sheet4, fmt.Sprintf("B%d", row), pos.ETFCode)
				f.SetCellValue(sheet4, fmt.Sprintf("C%d", row), pos.Shares)
				f.SetCellValue(sheet4, fmt.Sprintf("D%d", row), pos.Price)
				f.SetCellValue(sheet4, fmt.Sprintf("E%d", row), pos.Value)
				f.SetCellValue(sheet4, fmt.Sprintf("F%d", row), pos.Weight*100)
				f.SetCellValue(sheet4, fmt.Sprintf("G%d", row), result.PortfolioValue)
				row++
			}
		}
	}

	f.SetActiveSheet(index1)
	f.DeleteSheet("Sheet1")

	if err := f.SaveAs(filename); err != nil {
		return err
	}

	fmt.Printf("回测结果已保存到 %s\n", filename)
	fmt.Printf("  - Sheet1: 资金曲线\n")
	fmt.Printf("  - Sheet2: 绩效指标\n")
	fmt.Printf("  - Sheet3: 交易记录 (%d笔，含ETF名称)\n", len(s.allTrades))
	fmt.Printf("  - Sheet4: 持仓明细 (当周实际持仓)\n")
	return nil
}

// 辅助函数
func parseFloat(s string) float64 {
	var f float64
	fmt.Sscanf(s, "%f", &f)
	return f
}

func stdDev(data []float64) float64 {
	if len(data) == 0 {
		return 0
	}

	mean := 0.0
	for _, v := range data {
		mean += v
	}
	mean /= float64(len(data))

	variance := 0.0
	for _, v := range data {
		variance += (v - mean) * (v - mean)
	}
	variance /= float64(len(data))

	return math.Sqrt(variance)
}

func calculateMaxDrawdown(results []BacktestResult) float64 {
	maxValue := results[0].PortfolioValue
	maxDD := 0.0

	for _, result := range results {
		if result.PortfolioValue > maxValue {
			maxValue = result.PortfolioValue
		}
		dd := (result.PortfolioValue - maxValue) / maxValue * 100
		if dd < maxDD {
			maxDD = dd
		}
	}

	return maxDD
}

